package proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * @Author forsake
 * @Description 动态代理的两种实现方式
 * JDK动态代理：利用反射机制生成一个实现代理接口的匿名类，在调用具体方法前调用InvokeHandler来处理。
 * CGlib动态代理：利用ASM（开源的Java字节码编辑库，操作字节码）开源包，将代理对象类的class文件加载进来，通过修改其字节码生成子类来处理。
 *
 * 区别：JDK代理只能对实现接口的类生成代理；CGlib是针对类实现代理，对指定的类生成一个子类，并覆盖其中的方法，这种通过继承类的实现方式，不能代理final修饰的类。
 **/
public class ProxyInvocationHandler implements InvocationHandler {
    private Object target;
    // 目标对象是活动的，不是固定的谁传就给谁代理
    public void setTarget(Object target) {
        this.target = target;
    }
    // 创建代理类
    public Object getProxy() {
//        类加载器为：sun.misc.Launcher$AppClassLoader@b4aac2
//        代理接口为：[Ljava.lang.Class;@15a1588
//        调用处理器为：com.example.动态代理.ProxyInvocationHandler@1116ca2
        System.out.println("类加载器为："+this.getClass().getClassLoader());
        System.out.println("代理接口为："+target.getClass().getInterfaces());
        System.out.println("调用处理器为："+ this);
        return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(),this);
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 功能增强
        log(method.getName());
        // 调用目标对象的方法
        Object result = method.invoke(target,args);
        return result;
    }
    public void log(String methodName){
        System.out.println("执行了" + methodName + "方法");
    }
}
